package com.alibaba.algo.components.yapi.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import com.alibaba.algo.components.yapi.annotations.ApiModelProperty;
import com.alibaba.algo.components.yapi.entity.Mock;
import com.alibaba.algo.components.yapi.entity.Node;

public class ClazzUtils {
	public static List<Node> getChildrenNodes(Class<?> clazz, Map<String, String> clazzMap) {
		List<Node> parentNodes = new ArrayList<Node>();
		if (simpleClass(clazz)) {
			Node node = new Node();
			node.setType(TypeConverter.getYapiType(clazz.getTypeName()));
			node.setFieldClazzName(clazz.getName());
			parentNodes.add(node);
			return parentNodes;
		}

		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			field.setAccessible(true);
			Class<?> fieldClass = field.getType();
			if (fieldClass.getName().equals("java.lang.reflect.Constructor")
					|| fieldClass.getName().equals("java.lang.Class")) {
				continue;
			}
			Node node = new Node();
			// 自定义注解
			ApiModelProperty apiModelProperty = field.getAnnotation(ApiModelProperty.class);
			if (apiModelProperty != null) {
				node.setDesc(apiModelProperty.value());
				node.setRequired(apiModelProperty.required());
				node.setMock(apiModelProperty.mock());
			}
			node.setType(TypeConverter.getYapiType(field.getGenericType().getTypeName()));
			node.setFieldClazzName(fieldClass.getName());
			node.setFieldName(field.getName());
			// && !clazzMap.containsKey(fieldClass.getName())
			if (!simpleClass(fieldClass)) {
				if (fieldClass == java.util.List.class || fieldClass == java.util.Set.class) {
					Type genericType = field.getGenericType();
					// 泛型参数类型
					if (genericType instanceof ParameterizedType) {
						ParameterizedType pt = (ParameterizedType) genericType;
						fieldClass = (Class<?>) pt.getActualTypeArguments()[0];
					}
				}
				node.setChildrenTree(getChildrenNodes(fieldClass, clazzMap));

				// if (!clazzMap.containsKey(fieldClass.getName())) {
				// clazzMap.put(fieldClass.getName(), field.getName());
				node.setChildrenTree(getChildrenNodes(fieldClass, clazzMap));
				// }
			}
			parentNodes.add(node);
		}
		return parentNodes;
	}

	public static Map<String, Object> read(List<Node> nodeList, Map<String, Object> map, Set<String> allRequired) {
		Map<String, Object> properties = new LinkedHashMap<String, Object>(nodeList.size());
		List<String> requiredList = new ArrayList<String>(nodeList.size());
		for (Node node : nodeList) {
			Map<String, Object> innerMap = new LinkedHashMap<String, Object>(4);
			innerMap.put("type", node.getType());
			innerMap.put("description", node.getDesc());
			if (StringUtils.isNoneEmpty(node.getMock())) {
				innerMap.put("mock", new Mock(node.getMock()));
			}
			if (node.isRequired() && StringUtils.isNotBlank(node.getFieldName())) {
				requiredList.add(node.getFieldName());
				allRequired.add(node.getFieldName());
			}
			if (!CollectionUtils.isEmpty(node.getChildrenTree())) {
				Map<String, Object> childrenMap = read(node.getChildrenTree(), new HashMap<String, Object>(),
						allRequired);
				if (node.getType().equals("array")) {
					Map<String, Object> itemMap = new LinkedHashMap<String, Object>(4);
					// 处理private List<Integer> sexList;这种情况
					if (node.getChildrenTree().size() == 1
							&& StringUtils.isEmpty(node.getChildrenTree().get(0).getFieldName())) {
						itemMap.put("type", node.getChildrenTree().get(0).getType());
					} else {
						itemMap.put("type", "object");
						itemMap.put("properties", childrenMap.get("properties"));
					}

					if (childrenMap.get("required") != null) {
						itemMap.put("required", childrenMap.get("required"));
					}
					innerMap.put("items", itemMap);
				} else {
					innerMap.put("properties", childrenMap.get("properties"));
					if (childrenMap.get("required") != null) {
						innerMap.put("required", childrenMap.get("required"));
					}
				}
			}
			properties.put(node.getFieldName(), innerMap);
		}
		map.put("properties", properties);
		if (!CollectionUtils.isEmpty(requiredList)) {
			map.put("required", requiredList);
		}
		return map;
	}

	/**
	 * 判断这个类是否是常用类型
	 * @param parameterType
	 * @return
	 */
	public static boolean simpleClass(Class<?> parameterType) {
		return parameterType == String.class || parameterType == Integer.class || parameterType == int.class
				|| parameterType == Double.class || parameterType == double.class || parameterType == Long.class
				|| parameterType == long.class || parameterType == Float.class || parameterType == float.class
				|| parameterType == Byte.class || parameterType == byte.class || parameterType == Boolean.class
				|| parameterType == boolean.class || parameterType == BigDecimal.class || parameterType == Date.class
				|| parameterType == java.time.LocalDateTime.class;
	}

	/**
	 * @Description: 获取@RequestMapping，@GetMapping,@PostMapping获取uri
	 * @author: malin
	 * @date: 2020-12-7 9:52:13
	 */
	public static String getMethodUri(Method method) {
		String uri = "";
		if (method.isAnnotationPresent(PostMapping.class)) {
			PostMapping postMapping = AnnotationUtils.findAnnotation(method, PostMapping.class);
			if (postMapping != null && postMapping.value() != null && postMapping.value().length > 0) {
				uri = postMapping.value()[0];
			}
		} else if (method.isAnnotationPresent(GetMapping.class)) {
			GetMapping getMapping = AnnotationUtils.findAnnotation(method, GetMapping.class);
			if (getMapping != null && getMapping.value() != null && getMapping.value().length > 0) {
				uri = getMapping.value()[0];
			}
		} else if (method.isAnnotationPresent(RequestMapping.class)) {
			RequestMapping requestMapping = AnnotationUtils.findAnnotation(method, RequestMapping.class);
			if (requestMapping != null) {
				if (requestMapping != null && requestMapping.value() != null && requestMapping.value().length > 0) {
					uri = uri + requestMapping.value()[0];
				}
			}
		}
		return uri;
	}

	public static void main(String[] args) {
		Map<String, String> clazzMap = new HashMap<String, String>();
		// System.out.println(JSON.toJSONString(getChildrenNodes(InterfaceRequestVO.class, clazzMap)));
		// System.out.println(JSON.toJSONString(clazzMap));
		//System.out.println(JSON.toJSONString(getChildrenNodes(Demo.class, clazzMap)));
	}
}
